/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2016年1月25日
 * V4.0
 */
package com.jphenix.share.tools;

import com.jphenix.share.util.SFilesUtil;
import com.jphenix.standard.docs.ClassInfo;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;

/**
 * 进程号工具
 * 
 * 2022-06-17 增加了执行命令行的方法
 * 
 * @author 马宝刚
 * 2016年1月25日
 */
@ClassInfo({"2022-06-17 10:26","进程号工具"})
public class PidUtil {

	

    /**
     * 写入当前进程号到文件中
     * @param basePath 文件夹路径
     * WEB-INF/lib/jphenix.pid
     * 2016年1月25日
     * @author 马宝刚
     */
    public static void writePidFile(String basePath) {
        if(basePath==null || basePath.length()<1) {
        	basePath = SFilesUtil.getBaseClassPath(PidUtil.class); //这是jar包路径（包含jar包文件名）
        	basePath = SFilesUtil.getFilePath(basePath,false);
        }
        String filePath = SFilesUtil.getAllFilePath("jphenix.pid",basePath);
        //获取文件
        File wFile = SFilesUtil.createFile(filePath);
        //进程号
        String pid = getPid();
        System.out.println("\n<<<<<Current ProcessID:["+pid+"]>>>>>");
        //写入进程号
        FileCopyTools.copyToFile(pid,"UTF-8",wFile,false);
    }
    
    
    /**
     * 写入当前进程号到文件中
     * 文件路径在 WEB-INF/lib/jphenix.pid
     * 2016年1月25日
     * @author 马宝刚
     */
    public static void writePidFile() {
        writePidFile(null);
    }

    
    /**
     * 获取当前进程号
     * @return 当前进程号
     * 2016年1月25日
     * @author 马宝刚
     */
    public static String getPid() {
        //当下语句针对windows操作系统
        String name = ManagementFactory.getRuntimeMXBean().getName();
        // get pid    
        String pid = name.split("@")[0];    
        return pid;
    }
    
    /**
     * 检测当前进程是否在运行中
     * @param pid 进程号
     * @return 当前进程是否运行中
     * 2016年8月4日
     * @author MBG
     */
    public static boolean hasPid(String pid) {
    	if(SysUtil.getSystemType()==SysUtil.TYPE_SYSTEM_LINUX) {
    		return hasPidForLinux(pid);
    	}
    	return hasPidForWindows(pid);
    }
    
    
    /**
     * 检测当前进程是否在运行中（Linux操作系统）
     * @param pid 进程号
     * @return 当前进程是否运行中
     * 2016年8月4日
     * @author MBG
     */
    protected static boolean hasPidForLinux(String pid) {
    	/*
    	 * 调用命令：
    	 * ps --pid 9100
    	 * 
    	 * 返回的信息：
    	 * PID TTY          TIME CMD
    	 * 9100 ?        00:02:41 supervisord
    	 */
    	//获取进程信息
    	List<String> reList = receiveCmd(execute("ps --pid "+pid,"/"),"UTF-8");
    	return reList.size() > 1;
    }
    
    /**
     * 检测当前进程是否在运行中（Windows操作系统）
     * @param pid 进程号
     * @return 当前进程是否运行中
     * 2016年8月4日
     * @author MBG
     */
    protected static boolean hasPidForWindows(String pid) {
    	/*
    	 * 调用命令：
    	 * tasklist /FI "PID eq 2396" /FO CSV"
    	 * 
    	 * 返回信息：
    	 * "映像名称","PID","会话名      ","会话#   ","内存使用 "
    	 * "wwbizsrv.exe","2396","Services","0","8,604 K"
    	 */
    	//获取进程信息
    	List<String> reList = receiveCmd(execute("tasklist /FI \"PID eq "+pid+"\" /FO CSV","/"),"GBK");
    	return reList.size() > 1;
    }
    
    
    /**
     * 终止进程
     * @param pid 进程号
     * 2016年8月4日
     * @author MBG
     */
    public static void killPid(String pid) {
    	if(SysUtil.getSystemType()==SysUtil.TYPE_SYSTEM_LINUX) {
    		killPidForLinux(pid);
    	}else {
    		killPidForWindows(pid);
    	}
    }
    
    
    /**
     * 终止进程（Linux操作系统）
     * @param pid 进程号
     * 2016年8月4日
     * @author MBG
     */
    protected static void killPidForLinux(String pid) {
    	execute("kill -9 /pid "+pid,"/");
    }
    
    /**
     * 终止进程（Windows操作系统）
     * @param pid 进程号
     * 2016年8月4日
     * @author MBG
     */
    protected static void killPidForWindows(String pid) {
    	execute("taskkill -f /pid "+pid,"/");
    }
    
    /**
     * 执行命令行
     * @param cmdLine   命令行字符串
     * @param basePath  执行命令行时的根路径
     * @param resEnc    返回信息的编码格式
     * @return          回执行结果行信息序列
     * 2022年6月17日
     * @author MBG
     */
    public static List<String> executeCmd(String cmdLine,String basePath,String resEnc){
    	return receiveCmd(execute(cmdLine,basePath),resEnc);
    }
    
    /**
     * 执行进程
     * @param programName 程序名（不带路径）
     * @param basePath 运行路径
     * @return 程序信息
     * 2016年8月4日
     * @author MBG
     */
    public static Process execute(String programName,String basePath) {
    	try {
    		return Runtime.getRuntime().exec(programName,null,new File(basePath));
    	}catch(Exception e) {
    		e.printStackTrace();
    	}
    	return null;
    }
    
    /**
     * 执行命令行获取到的返回信息
     * @param proc 进程对象
     * @param enc  读取信息编码格式
     * @return 收到的返回信息序列
     * 2016年8月4日
     * @author MBG
     */
    public static List<String> receiveCmd(Process proc,String enc){
    	if(enc==null || enc.length()<1) {
    		enc = "UTF-8";
    	}
    	//构建返回值
    	List<String> reList = new ArrayList<String>();
    	if(proc==null) {
    		return reList;
    	}
    	//缓存读取类
    	BufferedReader bf = null;
    	try {
    		bf = new BufferedReader(new InputStreamReader(proc.getInputStream(),enc));
    		String line;
    		while((line=bf.readLine())!=null) {
    			reList.add(line);
    		}
    	}catch(Exception e) {
    		e.printStackTrace();
    	}finally {
    		try {
    			bf.close();
    		}catch(IOException e) {}
    	}
    	return reList;
    }
    
    public static void main(String[] args) {
    	hasPidForWindows("2396");
    }
}
